﻿using Deployment.Data.Environment.Connection;
using Deployment.Data.SQL.Connections;
using Deployment.Data.Variable;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

namespace Deployment.Data.SQL.Variable
{
    public class SQLConnectionVariable : AbstractVariable
    {
        public enum ConnectionValueSource 
        {
            NotDefined,
            DatabaseName,
            SQLServer,
            UserName,
            Password,
            ConnectionString,
        }

        private const string VALUESOURCE_ELEMENT = "ValueSource";
        private const string NOTDEFINED = "<Not Defined>";
        private const string DATABASENAME = "Database Name";
        private const string SQLSERVER = "SQL Server";
        private const string SQLUSER = "SQL User name";
        private const string PASSWORD = "SQL User's Password";
        private const string CONNECTIONSTRING = "Connection String";

        private static readonly List<string> valuesList = new List<string>()
        {
            NOTDEFINED,
            DATABASENAME,
            SQLSERVER,
            SQLUSER,
            PASSWORD,
            CONNECTIONSTRING
        };
        
        public static List<string> VisableSelectionList()
        {
            return valuesList;
        }

        private static ConnectionValueSource getFromStringValue(string stringValue)
        {
            if (stringValue == null)
                return ConnectionValueSource.NotDefined;
            else if (stringValue.Equals(NOTDEFINED))
                return ConnectionValueSource.NotDefined;
            else if (stringValue.Equals(SQLSERVER))
                return ConnectionValueSource.SQLServer;
            else if(stringValue.Equals(DATABASENAME))
                return ConnectionValueSource.DatabaseName;
            else if(stringValue.Equals(SQLUSER))
                return ConnectionValueSource.UserName;
            else if (stringValue.Equals(PASSWORD))
                return ConnectionValueSource.Password;
            else
                return ConnectionValueSource.NotDefined;
        }

        private static string ConvertToStringValue(ConnectionValueSource value)
        {
            switch (value)
            {
                case ConnectionValueSource.NotDefined:
                    return NOTDEFINED;
                case ConnectionValueSource.DatabaseName:
                    return DATABASENAME;
                case ConnectionValueSource.SQLServer:
                    return SQLSERVER;
                case ConnectionValueSource.UserName:
                    return SQLUSER;
                case ConnectionValueSource.Password:
                    return PASSWORD;
                case ConnectionValueSource.ConnectionString:
                    return CONNECTIONSTRING;
                default:
                    return NOTDEFINED;
            }
        }

        private bool _internalSet = false;

        public SQLConnectionVariable()
            : base()
        {
            base.PropertyChanged += SQLConnectionVariable_PropertyChanged;
        }

        void SQLConnectionVariable_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName.Equals("Extra") && !_internalSet)
                OnPropertyChanged("SourceType");
        }

        [XmlIgnore()]
        public ConnectionValueSource SourceType
        {
            get { return getFromStringValue(Extra); }
            set
            {
                _internalSet = true;
                Extra = ConvertToStringValue(value);
                OnPropertyChanged("SourceType");
                _internalSet = false;
            }
        }

        protected override string calculateValue()
        {
            if (Environment == null)
                throw new ArgumentException("ActualValue cannot be calculated while an environment is null.");
            List<AbstractConnection> connections = Environment.getConnectionsByName(Value);
            if (connections.Count > 0)
                throw new ArgumentException(string.Format("Multiple connections with the name of [{0}] exist in Environment [{1}], value cannot be calculated.", Value, Environment.Name));
            AbstractConnection con = connections[0];
            if (!(con is AbstractSQLConnection))
                throw new Exception(string.Format("Connection name [{1}] must be an instance of AbstractSQLConnection!", Value));
            AbstractSQLConnection sqlConnection = con as AbstractSQLConnection;
            switch (SourceType)
            {
                case ConnectionValueSource.ConnectionString:
                    return sqlConnection.Data;
                case ConnectionValueSource.DatabaseName:
                    if (!(sqlConnection is SQLDatabaseConnection))
                        throw new ArgumentException(string.Format("Connection [{0}] is a SQL Server connection with no database context", sqlConnection.Name));
                    return (sqlConnection as SQLDatabaseConnection).DatabaseName;
                case ConnectionValueSource.SQLServer:
                    return sqlConnection.SQLServer;
                case ConnectionValueSource.UserName:
                    if(sqlConnection.IntegratedSecurity)
                        return null;
                    return sqlConnection.User;
                case ConnectionValueSource.Password:
                    if (sqlConnection.IntegratedSecurity)
                        return null;
                    return sqlConnection.Password;
                default:
                    return null;
            }
        }

        

        protected override string getTypeDescriptionName()
        {
            return "SQL Connection Variable";
        }

        protected override bool performContentCheck()
        {
            return (!string.IsNullOrEmpty(Extra) && !string.IsNullOrEmpty(Value));
        }

        
        protected override AbstractVariableEditorControl createControl()
        {
            return new UI.SQLConnectionVariableControl2();
        }
    }
}
